package com.example.demo.game;

import com.example.demo.JavaGobangApplication;
import com.example.demo.entity.User;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.annotation.Resource;
import lombok.Data;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;

import java.io.IOException;
import java.util.UUID;

// 表示一个房间
@Data
public class Room {

    private OnlineUserMapper onlineUserMapper;

    private RoomManager roomManager;

    private ObjectMapper objectMapper = new ObjectMapper();


    //字符串类型表示，方便生成唯一值
    private String roomId;
    private User user1;
    private User user2;
    private int whiteUser;
    private static final int MAX_ROW = 15;
    private static final int MAX_COL = 15;

    // 表示棋盘 0 未落子  1 user1落子位置  2 user2落子位置
    private int[][] board  = new int[MAX_ROW][MAX_COL];

    public Room() {
        roomId = UUID.randomUUID().toString();
        // 通过入口类记录的context 来手动获取
        onlineUserMapper = JavaGobangApplication.context.getBean(OnlineUserMapper.class);
        roomManager = JavaGobangApplication.context.getBean(RoomManager.class);
    }

    /**
     * 通过这个方法来处理一次落子操作
     * @param reqJson
     */
    public void putChess(String reqJson) throws IOException {
        // 1. 记录当前落子的位置
        GameRequest request = objectMapper.readValue(reqJson,GameRequest.class);
        GameResponse response = new GameResponse();
        //判断是哪个玩家落的子
        int chess = request.getUserId() == user1.getUserId()? 1 : 2;
        int row = request.getRow();
        int col = request.getCol();
        // 判断这个位置是否有子
        if (board[row][col] != 0) {
            System.out.println("当前位置 （" + row +"," + col+")" + "已经有子！" );
            return;
        }
        board[row][col] = chess;

        //打印棋盘信息
        printBoard();
        // 2. 进行胜负判定

        int winner = checkWinner(row,col,chess);

        // 3，给房间中所有客户端返回响应

        response.setMessage("putChess");
        response.setRow(row);
        response.setCol(col);
        response.setUserId(request.getUserId());
        response.setWinner(winner);
        // 获取到房间的用户的WebSocket会话
        WebSocketSession session1 = onlineUserMapper.getFromGameRoom(user1.getUserId());
        WebSocketSession session2 = onlineUserMapper.getFromGameRoom(user2.getUserId());
        // 判断
        if (session1 == null) {
            //玩家1 掉线 玩家2获胜
            response.setWinner(user2.getUserId());
            System.out.println("玩家1 掉线！");
        }
        if (session2 == null) {
            response.setWinner(user1.getUserId());
            System.out.println("玩家2 掉线！");
        }

        String respJson = objectMapper.writeValueAsString(response);
        if (session1 != null) {
            session1.sendMessage(new TextMessage(respJson));
        }
        if (session2 != null) {
            session2.sendMessage(new TextMessage(respJson));
        }

        // 若胜负已分 则从房间管理器中移除房间

        if (response.getWinner() != 0)  {
            System.out.println("游戏结束！ 房间即将销毁！ roomId=" + roomId+"获胜方：" + response.getWinner() );
            roomManager.remove(roomId,user1.getUserId(),user2.getUserId());
        }


    }

    private void printBoard() {

        //打印棋盘
        System.out.println("[打印棋盘信息]  [房间号] " + roomId);
        System.out.println("===================================================================");
        for (int r = 0; r < MAX_ROW; r++) {
            for (int c = 0; c < 15; c++) {
                System.out.print(board[r][c] + " ");
            }
            System.out.println();
        }
        System.out.println("===================================================================");

    }


    //todo  判断当前落子是否分出胜负 返回获胜者的id  未分出胜负返回0
    private int checkWinner(int row, int col,int chess) {
        // 1. 检查所有行
        for (int c = col - 1; c <= col ; c++) {

            try {
                if(board[row][c] == chess
                    && board[row][c + 1] ==chess
                        && board[row][c + 2] ==chess
                        && board[row][c + 3] ==chess
                        && board[row][c + 4] ==chess) {
                    return chess == 1 ?  user1.getUserId() : user2.getUserId();
                }
            } catch (ArrayIndexOutOfBoundsException e) {
                continue;
            }
        }
        // 2. 检查列
        for (int r = row - 4; r <= row ; r++) {
            try {
                if( board[r][col] == chess
                       && board[r + 1] [col] == chess
                        && board[r + 2] [col] == chess
                        && board[r + 3] [col] == chess
                        && board[r + 4] [col] == chess) {
                    return chess == 1 ?  user1.getUserId() : user2.getUserId();

                }
            }catch (ArrayIndexOutOfBoundsException e) {
                continue;
            }
        }
        // 3. 检查对角线
        for (int r = row - 4,c = col - 4;r <= row && c <= col;c++,r++) {
            try{
                if(board[r][c] == chess
                      && board[r + 1] [c + 1] == chess
                        && board[r + 2] [c + 2] == chess
                        && board[r + 3] [c + 3] == chess
                        && board[r + 4] [c + 4] == chess) {
                    return chess == 1 ?  user1.getUserId() : user2.getUserId();

                }
            } catch (ArrayIndexOutOfBoundsException e) {
                continue;
            }
        }
        for (int r = row - 4,c = col + 4;r <= row && c >= col;c--,r++) {
            try{
                if(board[r][c] == chess
                        && board[r + 1] [c - 1] == chess
                        && board[r + 2] [c - 2] == chess
                        && board[r + 3] [c - 3] == chess
                        && board[r + 4] [c - 4] == chess) {
                    return chess == 1 ?  user1.getUserId() : user2.getUserId();

                }
            } catch (ArrayIndexOutOfBoundsException e) {
                continue;
            }
        }

        return 0;
    }
}
